package ru.rchervot.sanasar.client.view;

import java.util.ArrayList;
import java.util.HashSet;

import ru.rchervot.sanasar.client.model.SearchResultsItem;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.Cell;

public abstract class AbstractResultsView extends Composite 
implements ResultsPresenter.Display, ClickHandler {
	
	private class Col0Widget extends FlowPanel {
		private final CheckBox checkBox = new CheckBox();
		private final HTML rowNumber = new HTML();
		
		Col0Widget () {
			super();
			
			this.add(checkBox);
			this.add(rowNumber);
			
			rowNumber.setStylePrimaryName("AbstractResultsView_Offset");
		}
		
		public CheckBox getCheckBox() {
			return checkBox;
		}
		
		public HTML getRowNumber() {
			return rowNumber;
		}
	}
	
	
	private static final int CHECKBOX_COLUMN = 0;
	private static final int MAIN_CONTENT_COLUMN = 1;
	private static final int LAST_COLUMN = 2;
	
	protected ArrayList<Widget> widgetsCol0 = new ArrayList<Widget>();
	protected ArrayList<Widget> widgetsCol1 = new ArrayList<Widget>();
	protected ArrayList<Widget> widgetsCol2 = new ArrayList<Widget>();
	
	protected Grid basePanel = new Grid(0, getColumnsCount());
	private Presenter presenter;
	private HashSet<Integer> selectedRows = new HashSet<Integer>();
	
	private final ArrayList<HasClickHandlers> checkBoxes = new ArrayList<HasClickHandlers>();
	
	public AbstractResultsView() {
		super();
		basePanel.setCellPadding(0);
		basePanel.setCellSpacing(0);
		
//		basePanel.setSize("100%", "100%");
		basePanel.setStylePrimaryName("AbstractResultsView");
				
		basePanel.getColumnFormatter().setWidth(CHECKBOX_COLUMN, "20px");
		basePanel.getColumnFormatter().setWidth(LAST_COLUMN, "100px");
				
		this.initWidget(basePanel);
		
		basePanel.addClickHandler(this);
	}

	protected abstract int getColumnsCount();
	
	@Override
	public void updateItems(ArrayList<SearchResultsItem> items, int pageOffset) {
		basePanel.setVisible(true);
		
		clearSelectedRows();
		
		for (int i = 0; i < basePanel.getRowCount(); i++) {
			if (i < items.size()) {
				updateCol0Widget(i, pageOffset + i + 1); // +1 for human convenience
				updateCol1Widget(i, items.get(i));
				updateCol2Widget(i, items.get(i));
				
				basePanel.getRowFormatter().setVisible(i, true);
			} else {
				basePanel.getRowFormatter().setVisible(i, false);
			}
		}
	}
	
	@Override
	public void resizeTable(int rows) { //TODO may be add proper cleaning?
		basePanel.resizeRows(rows);
		
		selectedRows.clear();
		checkBoxes.clear();
		
		widgetsCol0 = new ArrayList<Widget>(rows);
		widgetsCol1 = new ArrayList<Widget>(rows);
		widgetsCol2 = new ArrayList<Widget>(rows);
		
		for (int i = 0; i < rows; i++) {
			basePanel.getCellFormatter().setAlignment(i, CHECKBOX_COLUMN, 
					HasHorizontalAlignment.ALIGN_CENTER, HasVerticalAlignment.ALIGN_TOP);
			basePanel.getCellFormatter().setAlignment(i, LAST_COLUMN, 
					HasHorizontalAlignment.ALIGN_RIGHT, HasVerticalAlignment.ALIGN_TOP);	
			
			widgetsCol0.add(i, createCol0Widget());
			widgetsCol1.add(i, createCol1Widget());
			widgetsCol2.add(i, createCol2Widget());
			
			basePanel.setWidget(i, 0, widgetsCol0.get(i));
			basePanel.setWidget(i, 1, widgetsCol1.get(i)); 
			basePanel.setWidget(i, 2, widgetsCol2.get(i));
		}
	}
	
	
	protected abstract Widget createCol1Widget();
	protected abstract Widget createCol2Widget();
	
	protected abstract void updateCol1Widget(int row, SearchResultsItem item);
	protected abstract void updateCol2Widget(int row, SearchResultsItem item);
	
	protected Col0Widget createCol0Widget() {
		Col0Widget w = new Col0Widget();
		
		checkBoxes.add(w.getCheckBox());
		w.getCheckBox().addClickHandler(this);
		
		return w;
	}
	
	private void updateCol0Widget(int row, int itemOffsetHuman) {
		((Col0Widget)widgetsCol0.get(row)).getRowNumber().setHTML(
				converNumberToVString(itemOffsetHuman));
	}
	
	private String converNumberToVString(int number) {
		String s = String.valueOf(number);
		StringBuffer sb = new StringBuffer();
				
		for (int i = 0; i < s.length(); i++) {
			sb.append(s.charAt(i) + "<br/>");
		}
		
		return sb.toString();
	}
	
	@Override
	public void selectSingleRow(int row) {
		if (alreadySelectedAndOnlyOne(row)) return;
		
		clearSelectedRows();
		
		selectedRows.add(row);
		
		for (int column = 0; column < getColumnsCount(); column++) {
			basePanel.getCellFormatter().setStylePrimaryName(row, column, "AbstractResultsView_Checked");
		}
		
		((CheckBox)checkBoxes.get(row)).setValue(true);
//		((CheckBox)basePanel.getWidget(row, CHECK_BOX_COLUMN)).setValue(true);
	}
	
	private boolean alreadySelectedAndOnlyOne(int row) {
		if (selectedRows.contains(row) && selectedRows.size() == 1) {
			return true;
		} else {
			return false;
		}
	}
	
	private void clearSelectedRows() {
		for (Integer row : selectedRows) {
			for (int column = 0; column < getColumnsCount(); column++) {
				basePanel.getCellFormatter().removeStyleName(row, column, "AbstractResultsView_Checked");
			}
			
			((CheckBox)checkBoxes.get(row)).setValue(false);
//			((CheckBox)basePanel.getWidget(row, CHECK_BOX_COLUMN)).setValue(false);
		}
		
		selectedRows.clear();
	}
	
	private void selectRow(int row, boolean selected) {
		if (selected) {
			selectedRows.add(row);
			
			for (int column = 0; column < getColumnsCount(); column++) {
				basePanel.getCellFormatter().setStylePrimaryName(row, column, "AbstractResultsView_Checked");
			}
		} else {
			selectedRows.remove(row);
			
			for (int column = 0; column < getColumnsCount(); column++) {
				basePanel.getCellFormatter().removeStyleName(row, column, "AbstractResultsView_Checked");
			}
		}
	}
	
	
	public void onClick(ClickEvent event) {
    // note that in general, events can have sources that are not Widgets.
    Widget sender = (Widget) event.getSource();

    if (sender instanceof CheckBox) {
      boolean checked = ((CheckBox)event.getSource()).getValue();
      
      Cell cell = basePanel.getCellForEvent(event);
      
			if (cell != null) {					
				selectRow(cell.getRowIndex(), checked);
			}
			
    event.stopPropagation(); // in order not to interfere with basePanel.addClickHandler()
  
    } else if (sender == basePanel) {
    	Cell cell = basePanel.getCellForEvent(event);
			
			if (cell != null) {					
				selectSingleRow(cell.getRowIndex());
			}
    }
  }
	
	@Override
	public int getRowOffsetHeight(int row) {
		int result = 0;
		
		for (int i = 0; i < row; i++) {
			result += basePanel.getWidget(row, MAIN_CONTENT_COLUMN).getOffsetHeight();
			result += Constants.kResultsRowBorder; 
		}

		return result;
	}
	
	@Override
	public void showEmptyPage() {
		basePanel.setVisible(false);
	}
	
	@Override
	public void showStartPage() {
		showEmptyPage();
	}
	
	@Override
	public HasClickHandlers getTable() {
		return basePanel;
	}
	
	@Override
	public ArrayList<HasClickHandlers> getCheckBoxes() {
		return checkBoxes;
	}
	
	@Override
	public HashSet<Integer> getSelectedRows() {
		return selectedRows;
	}
	
	@Override
	public void setPresenter(Presenter presenter) {
		this.presenter = presenter;
	}
}
